#ifndef __VEC_HH__
#define __VEC_HH__

#include <cassert>

template< typename T, T v0, T v2 >
struct value_checker;

template< typename T, T v3 >
struct value_checker< T, v3, v3 >
{
};

template< typename T, T v3, T v4 >
struct value_checker< T, v3, v4 >;

template< typename T, int dim >
class vec
{
   public: // const types & values
      typedef T data_type;
      enum{ size = dim };
      
   public: // ctor & dtor
      vec( void )
      {
         memset( _array, 0, dim * sizeof( T ) );
      }
      
      vec( const T& v0, const T& v1 )
      {
         value_checker< int, 2, dim >();
         _array[ 0 ] = v0;
         _array[ 1 ] = v1;
      }
      
      vec( const T& v0, const T& v1,
           const T& v2 ) 
      {
         value_checker< int, 3, dim >();
         _array[ 0 ] = v0; _array[ 1 ] = v1;
         _array[ 2 ] = v2;
      }
      
      vec( const T& v0, const T& v1,
           const T& v2, const T& v3 )       
      {
         value_checker< int, 4, dim >();
         _array[ 0 ] = v0; _array[ 1 ] = v1;
         _array[ 2 ] = v2; _array[ 2 ] = v3;      
      }
      
      vec( const T v[ dim ] )
      {
         memcpy( _array, v, dim * sizeof( T ) );
      }
      
      vec( const vec& in )
      {
         memcpy( _array, in._array, dim * sizeof( T ) );
      }
      
   public: // public methods
      vec& operator=( const vec& in )
      {
         memcpy( _array, in._array, dim * sizeof( T ) );
      }
      
      vec& operator*=( const vec& in )
      {
         for( size_t i = 0; i < dim; ++i ) { _array[ i ] *= in._array[ i ]; }
         return *this;
      }
      
      vec operator*( const vec& in )
      {
         vec ret( *this ); ret *= in; return ret;
      }
      
      vec& operator+=( const vec& in )
      {
         for( size_t i = 0; i < dim; ++i ) { _array[ i ] += in._array[ i ]; }
      }
      
      vec operator+( const vec& in )
      {
         vec ret( *this ); ret += in; return ret;
      }
      
      vec& operator-=( const vec& in )
      {
         for( size_t i = 0; i < dim; ++i ) { _array[ i ] -= in._array[ i ]; }
      }
      
      vec operator-( const vec& in )
      {
         vec ret( *this ); ret -= in; return ret;
      }
      
      vec& operator/=( const vec& in )
      {
         for( size_t i = 0; i < dim; ++i ) { _array[ i ] /= in._array[ i ]; }
      }
      
      vec operator/( const vec& in )
      {
         vec ret( *this ); ret /= in; return ret;
      }

      T& operator[]( const size_t& index )
      {      
         return _array[ index ];
      }
      
      const T& operator[]( const size_t& index ) const
      {      
         return _array[ index ];
      }
                      
   private:
      T _array[ dim ]; //!< data array
};


#endif